package com.chb.docter.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chb.docter.dto.RegistrationDto;
import com.chb.docter.dto.SchedulingDto;
import com.chb.docter.feigns.DeptFeign;
import com.chb.docter.feigns.UserFeign;
import com.chb.docter.mapper.SchedulingMapper;
import com.chb.docter.params.SchedulingAndPatientParam;
import com.chb.docter.params.SchedulingParam;
import com.chb.docter.params.SchedulingSaveParam;
import com.chb.docter.service.SchedulingService;
import com.hos.entity.his.Scheduling;
import com.hos.entity.sys.Dept;
import com.hos.entity.sys.User;
import com.hos.utils.WebUtil;
import com.hos.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 陈海彬
 * @date: Created in 2023/12/11 19:57
 * @description:
 * @modified By:
 * @version:
 */
@Service
public class SchedulingServiceImpl implements SchedulingService {

    @Resource
    private SchedulingMapper schedulingMapper;
    @Resource
    private UserFeign userFeign;
    @Resource
    private DeptFeign deptFeign;

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Override
    public Result<Map<String, Object>> getSchedulingList(SchedulingParam schedulingParam) {
        // 1.根据条件查询值班医生信息
        Map<String, Object> params = new HashMap<>();
        params.put("userId", schedulingParam.getUserId());
        params.put("deptId", schedulingParam.getDeptId());
        List<User> users = userFeign.getUser(params);
        return findResult(schedulingParam, users);
    }

    @Override
    public boolean saveScheduling(SchedulingSaveParam params) {
        // 获取值班日期
        String beginDate = params.getBeginDate();
        // 获取医生id
        Long userId = params.getData().get(0).getUserId();
        // 获取科室id
        Long deptId = params.getData().get(0).getDeptId();
        List<SchedulingDto> paramsData = params.getData();

        // 1.进行删除这个一周值班医生的数据
        deleteScheduling(userId, beginDate);

        // 2.进行添加排班信息
        for (SchedulingDto paramsDatum : paramsData) {
            // 获取排班时段    1上午 2下午 3晚上
            String subsectionType = paramsDatum.getSubsectionType();
            // 获取排班类型    1门诊  2急诊
            Collection<String> schedulingTypes = paramsDatum.getSchedulingType();
            List<String> schedulingList = new ArrayList<>(schedulingTypes);

            for (int i = 0; i < schedulingTypes.size(); i++) {
                String schedulingType = schedulingList.get(i);
                if (StringUtils.hasText(schedulingType)) {
                    // 进行添加操作
                    Scheduling scheduling = new Scheduling();
                    scheduling.setUserId(userId);                               // 设置医生Id
                    scheduling.setDeptId(deptId);                               // 设置科室Id
                    DateTime time = DateUtil.offsetDay(DateUtil.parse(beginDate, "yyyy-MM-dd"), i);
                    scheduling.setSchedulingDay(DateUtil.format(time, "yyyy-MM-dd"));     // 设置值班日期
                    scheduling.setSubsectionType(subsectionType);               // 设置排班时段
                    scheduling.setSchedulingType(schedulingType);               // 设置排班类型
                    scheduling.setCreateTime(new Date());                       // 设置创建时间
                    scheduling.setCreateBy(getUserByToken().getUserName());     // 设置创建者
                    this.schedulingMapper.insert(scheduling);
                }
            }
        }
        return true;
    }

    @Override
    public List<RegistrationDto> findSchedulingList(SchedulingAndPatientParam params) {
        LambdaQueryWrapper<Scheduling> wrapper = new LambdaQueryWrapper<>();
        List<RegistrationDto> registrationDtos = new ArrayList<>();
        // 进行条件查询
        if (Objects.nonNull(params.getDeptId())) {
            wrapper.eq(Scheduling::getDeptId, params.getDeptId());
        }
        if (StringUtils.hasText(params.getSchedulingDay())) {
            DateTime dateTime = DateUtil.parse(params.getSchedulingDay(), "yyyy-MM-dd");
            wrapper.eq(Scheduling::getSchedulingDay, DateUtil.format(dateTime, "yyyy-MM-dd"));
        }
        if (StringUtils.hasText(params.getSubsectionType())) {
            wrapper.eq(Scheduling::getSubsectionType, params.getSubsectionType());
        }
        if (StringUtils.hasText(params.getSchedulingType())) {
            wrapper.eq(Scheduling::getSchedulingType, params.getSchedulingType());
        }
        List<Scheduling> schedulingList = this.schedulingMapper.selectList(wrapper);
        // 设置返回信息
        if (schedulingList.size() > 0) {
            for (Scheduling scheduling : schedulingList) {
                // 科室id
                Long deptId = scheduling.getDeptId();
                // 通过科室获取科室信息
                Dept dept = deptFeign.selectDeptByDeptId(deptId);
                if (dept != null) {
                    RegistrationDto registrationDto = new RegistrationDto(deptId, dept.getDeptName(), dept.getRegNumber());
                    registrationDtos.add(registrationDto);
                }
            }
        }
        return registrationDtos.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public List<User> queryUsersNeedScheduling(Long deptId) {
        return this.userFeign.selectAllUser();
    }

    @Override
    public Result<Map<String, Object>> queryMyScheduling(SchedulingParam schedulingParam) {
        // 1.获取当前的时间
        DateTime date = DateUtil.date();

        // 2.判断前端查询时是否传递时间
        if (StringUtils.hasText(schedulingParam.getQueryDate())) {
            DateTime dateTime = DateUtil.parse(schedulingParam.getQueryDate(), "yyyy-MM-dd");
            // 判断传递的时间是周日还是周一    周日：1    周一：2
            int ofWeek = DateUtil.dayOfWeek(dateTime);
            if (ofWeek == 1) {  // 表示周日
                date = DateUtil.offsetDay(dateTime, 1);
            } else {
                date = DateUtil.offsetDay(dateTime, -1);
            }
        }


        // 3.获取指定日期所在周的周一和周日的日期
        DateTime begin = DateUtil.beginOfWeek(date);
        DateTime end = DateUtil.endOfWeek(date);

        // 4.封装到 SchedulingParam 中
        schedulingParam.setBeginDate(DateUtil.format(begin, "yyyy-MM-dd"));
        schedulingParam.setEndDate(DateUtil.format(end, "yyyy-MM-dd"));

        // 5.查询排班表
        List<Scheduling> schedulings = selectSchedulingByParams(schedulingParam);
        List<SchedulingDto> schedulingDtos = new ArrayList<>();

        Long userId1 = schedulingParam.getUserId();
        // 6.遍历值班人员信息
        User user = null;
        if (userId1 != null) {
            user = userFeign.getUserById(userId1);
        } else {
            // 6.遍历值班人员信息
            user = getUserByToken();
        }

        System.out.println("------user1---------"+user);


        // 初始化每个时间段的表格
        SchedulingDto dto1 = new SchedulingDto(user.getUserId(), user.getDeptId(), "1", initBetweenTimeMap(begin));
        SchedulingDto dto2 = new SchedulingDto(user.getUserId(), user.getDeptId(), "2", initBetweenTimeMap(begin));
        SchedulingDto dto3 = new SchedulingDto(user.getUserId(), user.getDeptId(), "3", initBetweenTimeMap(begin));
        for (Scheduling scheduling : schedulings) {
            // 值班人员的id
            Long userId = scheduling.getUserId();
            // 获取值班的时间
            String schedulingDay = scheduling.getSchedulingDay();
            // 值班的时间段
            String subsectionType = scheduling.getSubsectionType();
            // 值班的类型
            String schedulingType = scheduling.getSchedulingType();
            if (user.getUserId().equals(userId)) {
                switch (subsectionType) {
                    case "1":
                        Map<String, String> record1 = dto1.getRecord();
                        record1.put(schedulingDay, schedulingType);
                        break;
                    case "2":
                        Map<String, String> record2 = dto2.getRecord();
                        record2.put(schedulingDay, schedulingType);
                        break;
                    case "3":
                        Map<String, String> record3 = dto3.getRecord();
                        record3.put(schedulingDay, schedulingType);
                        break;
                }
            }
        }
        dto1.setSchedulingType(dto1.getRecord().values());
        dto2.setSchedulingType(dto2.getRecord().values());
        dto3.setSchedulingType(dto3.getRecord().values());
        schedulingDtos.add(dto1);
        schedulingDtos.add(dto2);
        schedulingDtos.add(dto3);

        // 7.获取日期头
        List<String> labelNames = initLabelNames(begin);

        // 8.返回相关信息
        Map<String, Object> map = new HashMap<>();
        map.put("labelNames", labelNames);
        map.put("beginDate", DateUtil.format(begin, "yyyy-MM-dd"));
        map.put("endDate", DateUtil.format(end, "yyyy-MM-dd"));
        map.put("tableData", schedulingDtos);
        return new Result<>(200, "查询成功", map);
    }

    @Override
    public Result<Map<String, Object>> AppQueryMyScheduling(SchedulingParam schedulingParam) {
        // 1.获取当前的时间
        DateTime begin = DateUtil.date();

        DateTime end = DateUtil.offsetDay(begin, 7);


        // 4.封装到 SchedulingParam 中
        schedulingParam.setBeginDate(DateUtil.format(begin, "yyyy-MM-dd"));
        schedulingParam.setEndDate(DateUtil.format(end, "yyyy-MM-dd"));

        // 5.查询排班表
        List<Scheduling> schedulings = selectSchedulingByParams(schedulingParam);
        List<SchedulingDto> schedulingDtos = new ArrayList<>();

        Long userId1 = schedulingParam.getUserId();
        // 6.遍历值班人员信息
        User user = null;
        if (userId1 != null) {
            user = userFeign.getUserById(userId1);
        } else {
            // 6.遍历值班人员信息
            user = getUserByToken();
        }


        // 初始化每个时间段的表格
        SchedulingDto dto1 = new SchedulingDto(user.getUserId(), user.getDeptId(), "1", initBetweenTimeMap(begin));
        SchedulingDto dto2 = new SchedulingDto(user.getUserId(), user.getDeptId(), "2", initBetweenTimeMap(begin));
        SchedulingDto dto3 = new SchedulingDto(user.getUserId(), user.getDeptId(), "3", initBetweenTimeMap(begin));
        for (Scheduling scheduling : schedulings) {
            // 值班人员的id
            Long userId = scheduling.getUserId();
            // 获取值班的时间
            String schedulingDay = scheduling.getSchedulingDay();
            // 值班的时间段
            String subsectionType = scheduling.getSubsectionType();
            // 值班的类型
            String schedulingType = scheduling.getSchedulingType();
            if (user.getUserId().equals(userId)) {
                switch (subsectionType) {
                    case "1":
                        Map<String, String> record1 = dto1.getRecord();
                        record1.put(schedulingDay, schedulingType);
                        break;
                    case "2":
                        Map<String, String> record2 = dto2.getRecord();
                        record2.put(schedulingDay, schedulingType);
                        break;
                    case "3":
                        Map<String, String> record3 = dto3.getRecord();
                        record3.put(schedulingDay, schedulingType);
                        break;
                }
            }
        }
        dto1.setSchedulingType(dto1.getRecord().values());
        dto2.setSchedulingType(dto2.getRecord().values());
        dto3.setSchedulingType(dto3.getRecord().values());
        schedulingDtos.add(dto1);
        schedulingDtos.add(dto2);
        schedulingDtos.add(dto3);

        // 7.获取日期头
        List<String> labelNames = AppinitLabelNames(begin);

        // 8.返回相关信息
        Map<String, Object> map = new HashMap<>();
        map.put("labelNames", labelNames);
        map.put("beginDate", DateUtil.format(begin, "yyyy-MM-dd"));
        map.put("endDate", DateUtil.format(end, "yyyy-MM-dd"));


        // 获取当前时间
        LocalTime currentTime = LocalTime.now();
        // 判断当前时间段
        if (currentTime.isBefore(LocalTime.NOON)) {
            System.out.println("当前时间是早上");
        } else if (currentTime.isBefore(LocalTime.of(18, 0))) {
            System.out.println("当前时间是中午");
        } else {
            System.out.println("当前时间是晚上");
        }

        map.put("tableData", schedulingDtos);


        return new Result<>(200, "查询成功", map);

    }

    /**
     * @return com.hos.entity.sys.User
     * @create by: 陈海彬
     * @description: 获取请求用户的信息
     * @create time: 2023/12/12 10:39
     */
    private User getUserByToken() {
        String token = WebUtil.getToken();
        String phone = redisTemplate.opsForValue().get("user:" + token);
        return userFeign.selectUserByPhone(phone);
    }

    /**
     * @param userId    医生id
     * @param beginDate 值班日期
     * @create by: 陈海彬
     * @description: 进行删除排班日期
     * @create time: 2023/12/12 10:39
     */
    private void deleteScheduling(Long userId, String beginDate) {
        // 获取结束日期
        DateTime endOfWeek = DateUtil.endOfWeek(DateUtil.parse(beginDate, "yyyy-MM-dd"));
        LambdaQueryWrapper<Scheduling> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(Scheduling::getUserId, userId);
        deleteWrapper.between(Scheduling::getSchedulingDay, beginDate, endOfWeek);
        this.schedulingMapper.delete(deleteWrapper);
    }

    private Result<Map<String, Object>> findResult(SchedulingParam schedulingParam, List<User> users) {
        // 封装值班的时间
        // 1.获取当前的时间
        DateTime date = DateUtil.date();

        // 2.判断前端查询时是否传递时间
        if (StringUtils.hasText(schedulingParam.getQueryDate())) {
            DateTime dateTime = DateUtil.parse(schedulingParam.getQueryDate(), "yyyy-MM-dd");
            // 判断传递的时间是周日还是周一    周日：1    周一：2
            int ofWeek = DateUtil.dayOfWeek(dateTime);
            if (ofWeek == 1) {  // 表示周日
                date = DateUtil.offsetDay(dateTime, 1);
            } else {
                date = DateUtil.offsetDay(dateTime, -1);
            }
        }


        // 3.获取指定日期所在周的周一和周日的日期
        DateTime begin = DateUtil.beginOfWeek(date);
        DateTime end = DateUtil.endOfWeek(date);

        // 4.封装到 SchedulingParam 中
        schedulingParam.setBeginDate(DateUtil.format(begin, "yyyy-MM-dd"));
        schedulingParam.setEndDate(DateUtil.format(end, "yyyy-MM-dd"));

        // 5.查询排班表
        List<Scheduling> schedulings = selectSchedulingByParams(schedulingParam);
        List<SchedulingDto> schedulingDtos = new ArrayList<>();

        // 6.遍历值班人员信息
        for (User user : users) {
            // 初始化每个时间段的表格
            SchedulingDto dto1 = new SchedulingDto(user.getUserId(), user.getDeptId(), "1", initBetweenTimeMap(begin));
            SchedulingDto dto2 = new SchedulingDto(user.getUserId(), user.getDeptId(), "2", initBetweenTimeMap(begin));
            SchedulingDto dto3 = new SchedulingDto(user.getUserId(), user.getDeptId(), "3", initBetweenTimeMap(begin));
            for (Scheduling scheduling : schedulings) {
                // 值班人员的id
                Long userId = scheduling.getUserId();
                // 获取值班的时间
                String schedulingDay = scheduling.getSchedulingDay();
                // 值班的时间段
                String subsectionType = scheduling.getSubsectionType();
                // 值班的类型
                String schedulingType = scheduling.getSchedulingType();
                if (user.getUserId().equals(userId)) {
                    switch (subsectionType) {
                        case "1":
                            Map<String, String> record1 = dto1.getRecord();
                            record1.put(schedulingDay, schedulingType);
                            break;
                        case "2":
                            Map<String, String> record2 = dto2.getRecord();
                            record2.put(schedulingDay, schedulingType);
                            break;
                        case "3":
                            Map<String, String> record3 = dto3.getRecord();
                            record3.put(schedulingDay, schedulingType);
                            break;
                    }
                }
            }
            dto1.setSchedulingType(dto1.getRecord().values());
            dto2.setSchedulingType(dto2.getRecord().values());
            dto3.setSchedulingType(dto3.getRecord().values());
            schedulingDtos.add(dto1);
            schedulingDtos.add(dto2);
            schedulingDtos.add(dto3);
        }

        // 7.获取日期头
        List<String> labelNames = initLabelNames(begin);

        // 8.返回相关信息
        Map<String, Object> map = new HashMap<>();
        map.put("labelNames", labelNames);
        map.put("beginDate", DateUtil.format(begin, "yyyy-MM-dd"));
        map.put("endDate", DateUtil.format(end, "yyyy-MM-dd"));
        map.put("tableData", schedulingDtos);
        return new Result<>(200, "查询成功", map);
    }

    /**
     * @param begin 开始时间
     * @return java.util.List<java.lang.String>
     * @create by: 陈海彬
     * @description: 初始化日期头
     * @create time: 2023/12/11 20:42
     */
    private List<String> initLabelNames(DateTime begin) {
        List<String> labelNames = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            DateTime dateTime = DateUtil.offsetDay(begin, i);
            String label = DateUtil.format(dateTime, "yyyy-MM-dd") + week(i);
            labelNames.add(label);
        }
        return labelNames;
    }

    /**
     * @param begin 开始时间
     * @return java.util.List<java.lang.String>
     * @create by: lqs
     * @description: 初始化日期头
     * @create time: 2023/12/11 20:42
     */
    private List<String> AppinitLabelNames(DateTime begin) {
        List<String> labelNames = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            DateTime dateTime = DateUtil.offsetDay(begin, i);
            Week week = DateUtil.dayOfWeekEnum(dateTime);
            String label = DateUtil.format(dateTime, "MM-dd") +week.toChinese().replace("星期","周");
            labelNames.add(label);
        }
        return labelNames;
    }

    // 获取当前日期的星期


    private String week(int i) {
        String week = "";
        switch (i) {
            case 0:
                week = "(周一)";
                break;
            case 1:
                week = "(周二)";
                break;
            case 2:
                week = "(周三)";
                break;
            case 3:
                week = "(周四)";
                break;
            case 4:
                week = "(周五)";
                break;
            case 5:
                week = "(周六)";
                break;
            case 6:
                week = "(周日)";
                break;
        }
        return week;
    }


    /**
     * @param begin 开始天数
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @create by: 陈海彬
     * @description: 初始化每个时间段的表格
     * @create time: 2023/12/11 20:34
     */
    private Map<String, String> initBetweenTimeMap(DateTime begin) {
        Map<String, String> treeMap = new TreeMap<>();
        for (int i = 0; i < 7; i++) {
            DateTime dateTime = DateUtil.offsetDay(begin, i);
            treeMap.put(DateUtil.format(dateTime, "yyyy-MM-dd"), "");
        }
        return treeMap;
    }


    /**
     * @param schedulingParam 排班时间
     * @return java.util.List<com.hos.entity.his.Scheduling>
     * @create by: 陈海彬
     * @description: 根据参数查询排班表
     * @create time: 2023/12/11 20:26
     */
    private List<Scheduling> selectSchedulingByParams(SchedulingParam schedulingParam) {
        LambdaQueryWrapper<Scheduling> wrapper = new LambdaQueryWrapper<>();

        // 1.进行条件查询
        if (Objects.nonNull(schedulingParam.getUserId())) {
            wrapper.eq(Scheduling::getUserId, schedulingParam.getUserId());
        }
        if (Objects.nonNull(schedulingParam.getDeptId())) {
            wrapper.eq(Scheduling::getDeptId, schedulingParam.getDeptId());
        }
        if (StringUtils.hasText(schedulingParam.getBeginDate())) {
            wrapper.between(Scheduling::getSchedulingDay, schedulingParam.getBeginDate(), schedulingParam.getEndDate());
        }

        return schedulingMapper.selectList(wrapper);
    }
}